#[macro_export]
macro_rules! srv_get_by_slug {
    ($fn:ident, $form:ident, $read_fn:expr) => {
        pub async fn $fn(pool: web::Data<DbPool>, slug: String) -> Result<$form, ServiceError> {
            let item = web::block(move || {
                let mut conn = pool.get()?;
                $read_fn(&mut conn, slug.clone())
            })
            .await??;
            Ok($form::from(&item))
        }
    };
}

#[macro_export]
macro_rules! srv_get_id {
    ($fn:ident, $form:ident, $read_fn:expr) => {
        pub async fn $fn(pool: web::Data<DbPool>, id: i32) -> Result<$form, ServiceError> {
            let item = web::block(move || {
                let mut conn = pool.get()?;
                $read_fn(&mut conn, id)
            })
            .await??;
            Ok($form::from(&item))
        }
    };
}

#[macro_export]
macro_rules! srv_get_id_in {
    ($fn:ident, $form:ident, $read_fn:expr) => {
        pub async fn $fn(
            pool: web::Data<DbPool>,
            ids: Vec<i32>,
        ) -> Result<Vec<$form>, ServiceError> {
            let items = web::block(move || {
                let mut conn = pool.get()?;
                $read_fn(&mut conn, ids)
            })
            .await??;
            Ok(items.iter().map($form::from).collect())
        }
    };
}

#[macro_export]
macro_rules! srv_get_all {
    ($fn:ident, $form:ident, $reads_fn:expr) => {
        pub async fn $fn(pool: web::Data<DbPool>) -> Result<Vec<$form>, ServiceError> {
            let items = web::block(move || {
                let mut conn = pool.get()?;
                $reads_fn(&mut conn, 8, 0)
            })
            .await??;
            Ok(items.iter().map($form::from).collect())
        }
    };
}

#[macro_export]
macro_rules! srv_get_all_by_slug {
    ($fn:ident, $form:ident, $slug2id_fn:expr, $target_id:ident, $get_fn:ident) => {
        pub async fn $fn(
            pool: web::Data<DbPool>,
            slug: String,
        ) -> Result<Vec<$form>, ServiceError> {
            let slug = $slug2id_fn(pool.clone(), slug.clone()).await?;
            let items = $get_fn(pool.clone(), slug.$target_id).await?;
            Ok(items)
        }
    };
}

#[macro_export]
macro_rules! srv_get_all_by_foreign_key {
    ($fn:ident, $form:ident, $read_fn:expr) => {
        pub async fn $fn(pool: web::Data<DbPool>, fk: i32) -> Result<Vec<$form>, ServiceError> {
            let items = web::block(move || {
                let mut conn = pool.get()?;
                $read_fn(&mut conn, fk, get_max_count().into(), 0)
            })
            .await??;
            Ok(items.iter().map($form::from).collect())
        }
    };
}

#[macro_export]
macro_rules! srv_get_in_page {
    ($fn:ident, $form:ident, $reads_fn:expr) => {
        pub async fn $fn(
            pool: web::Data<DbPool>,
            count: i32,
            page: i32,
        ) -> Result<Vec<$form>, ServiceError> {
            let offset = count * (page - 1);
            let items = web::block(move || {
                let mut conn = pool.get()?;
                $reads_fn(&mut conn, count.into(), offset.into())
            })
            .await??;
            Ok(items.iter().map($form::from).collect())
        }
    };
}

#[macro_export]
macro_rules! srv_get_in_page_by_slug {
    ($fn:ident, $form:ident, $slug2id_fn:expr, $target_id:ident, $get_fn:ident) => {
        pub async fn $fn(
            pool: web::Data<DbPool>,
            slug: String,
            count: i32,
            page: i32,
        ) -> Result<Vec<$form>, ServiceError> {
            let slug = $slug2id_fn(pool.clone(), slug.clone()).await?;
            let items = $get_fn(pool.clone(), slug.$target_id, count.into(), page.into()).await?;
            Ok(items)
        }
    };
}

#[macro_export]
macro_rules! srv_get_in_page_by_foreign_key {
    ($fn:ident, $form:ident, $read_fn:expr) => {
        pub async fn $fn(
            pool: web::Data<DbPool>,
            fk: i32,
            count: i32,
            page: i32,
        ) -> Result<Vec<$form>, ServiceError> {
            let offset = count * (page - 1);
            let items = web::block(move || {
                let mut conn = pool.get()?;
                $read_fn(&mut conn, fk, count.into(), offset.into())
            })
            .await??;
            Ok(items.iter().map($form::from).collect())
        }
    };
}

#[macro_export]
macro_rules! srv_get_slug_relation {
    ($fn:ident, $form:ident, $get_relation_fn:ident, $target_id:ident, $get_fn:expr) => {
        pub async fn $fn(
            pool: web::Data<DbPool>,
            slug: String,
        ) -> Result<Vec<$form>, ServiceError> {
            let relations = $get_relation_fn(pool.clone(), slug.clone()).await?;
            let ids = relations.iter().map(|item| item.$target_id).collect();
            let items = $get_fn(pool.clone(), ids).await?;
            Ok(items)
        }
    };
}
